
%%

%byaccj
%line
%column
%ignorecase

%{

  Parser parser;
  // cross coupling, lexer has an instance of parser, and parser
  // do have an instance of lexer. they work as producer-consumer pair
  // lexer produce tokex. scanner consumes it
  public Yylex(java.io.Reader r, Parser p) {
    this(r);
    this.parser = p;
  }
  
  public Integer yyline() {
  	return new Integer(yyline + 1);
  }

  public Integer yycolumn() {
  	return new Integer(yycolumn + 1);
  }

%}

ASSIGN = "="
MUL = "*"
DIV = "/"
PLUS = "+"
MINUS = "-"
LEFT = "("
RIGHT = ")"
POWER = "^"
FACT = "!"

NE = "<>"
EQ = "="
GE = ">="
LE = "<="
LT = "<"
GT = ">"

SEMI = ";"
COMMA = ","
COLON = ":"
HASH = "#"

ERROR = "error"

CR = "\n"

DIGIT = [0-9]+
LETTER = [a-zA-Z_$%.]
WHITESPACE= [\ \t]

// a float number
NUMBER = ({DIGIT} ("." {DIGIT}*)?) | ("." {DIGIT}+) /* digit, digit.digit, or .digit */

FILENUMBER = "#" {DIGIT}+

ID = {LETTER} ({LETTER} | {DIGIT})*

STRINGTEXT = (\\\"|[^\n\"]|\\{WHITESPACE}+\\)*
STRING = \" {STRINGTEXT} \"

%%

{ASSIGN} { return Parser.ASSIGN; }
{MUL} { return Parser.MUL; }
{DIV} { return Parser.DIV; }
{PLUS} { return Parser.PLUS; }
{MINUS} { return Parser.MINUS; }
{LEFT} { return Parser.LEFT; }
{RIGHT} { return Parser.RIGHT; }
{POWER} { return Parser.POWER; }
{FACT} { return Parser.FACT; }

{SEMI} { return Parser.SEMI; }
{COMMA} { return Parser.COMMA; }

{NE} { return Parser.NE; }
{EQ} { return Parser.EQ; }
{GE} { return Parser.GE; }
{LE} { return Parser.LE; }
{LT} { return Parser.LT; }
{GT} { return Parser.GT; }

// add 0 before any digit
{NUMBER} { parser.yylval = new ParserVal("0" + yytext()); return Parser.NUMBER; }

{FILENUMBER} { parser.yylval = new ParserVal(yytext().substring(1)); return Parser.FILENUMBER; }

// for IDentifiers, yytext() is the name, and Parser.ID is the type
{ID} { 
    short j = WorkSpace.lookup(yytext());
    if(j == Parser.ID) {
        parser.yylval = new ParserVal(yytext());
    }
    return j;
}

{STRING} {
    StringBuffer sb = new StringBuffer(yytext());
    sb.deleteCharAt(0); // remove the double quotes
    sb.deleteCharAt(sb.length() - 1);
    parser.yylval = new ParserVal(sb.toString());
    return Parser.STRING;
}

"'".* { ; } // comment style: "' comment text"
"REM".* { ; } // comment style: "REM comment text"

// new line, and colon separate statements
"\n" | "\r" | "\r\n" | ":" { return Parser.CR; }
[ \t] { ; }

// otherwise, return error (NEEDS REVISION)
. { parser.yyerror("unknown character"); }